#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <cstring>
#include <cstdio>
#include <unistd.h>
#include <cstdlib>

using namespace std;

#include "TApplication.h"
#include "TFile.h"
#include "TTree.h"
#include "TRandom3.h"
#include "TMath.h"
#include "TH1I.h"
#include "TStyle.h"
#include "TPad.h"
#include "TGaxis.h"
#include "TCanvas.h"
#include "TAxis.h"
#include <yaml-cpp/yaml.h>

#include "setup.h"
using namespace std;
double getChOffset(int iCh, int iCh_basic = 0, int Nnum = 1000)
{
	TH1D *hChOffset = new TH1D();
	for (int i = 0; i < Nnum; i++)
	{
		hChOffset->Fill(iCh_basic * iCh + i, 1);
	}
	double offset = 0;
	return offset;
}

void Coin2Ana_ToF()
{
	gStyle->SetOptStat(kFALSE);
	gStyle->SetPadGridX(1);
	gStyle->SetPadGridY(1);

	int i = 0, j = 0, k = 0, m = 0, n = 0, p = 0, q = 0;
	double x = 0.0, y = 0.0, z = 0.0;

	clock_t start, finish;

	if (access("../AnaData", F_OK) != 0)
		system("mkdir ../AnaData");

	if (access("../Graphs", F_OK) != 0)
		system("mkdir ../Graphs");

	string strRead;
	// ifstream fileName("../config/ListRuns_ToF.txt");
	for (auto sRun_ToF : finalFileName)
	{

		start = clock();

		string sCoin = "../RootData/ToF_Sort_Coin_" + sRun_ToF + ".root";
		string sAna = "../AnaData/ToF_Ana_" + sRun_ToF + ".root";
		printf("\n**********Now converting %s to %s!**********\n\n", sCoin.c_str(), sAna.c_str());

		TFile *fCoin = new TFile(sCoin.c_str());
		if (fCoin->IsZombie())
		{
			cout << "Error in opening " << sCoin << "!\n";
			delete fCoin;
			continue;
		}
		TTree *treeCoin_ToF;
		fCoin->GetObject("treeCoin_ToF", treeCoin_ToF);
		if (!treeCoin_ToF)
		{
			cout << "Error read the tree of treeCoin_ToF!\n";
			continue;
		}
		treeCoin_ToF->SetEstimate(-1);

		short nCoin_ToF = 0, nHit_ToF[NBD_ToF][NCH_ToF] = {0}, tsFine_ToF[NBD_ToF][NCH_ToF][NMaxHit_ToF] = {0};
		long long tsSlc0_ToF = 0;
		double tmStp0_ToF = 0;
		double tmCrs_ToF[NBD_ToF][NCH_ToF][NMaxHit_ToF] = {0};
		long long tsSlc_ToF[NBD_ToF][NCH_ToF][NMaxHit_ToF] = {0};
		double tmStp_ToF[NBD_ToF][NCH_ToF][NMaxHit_ToF] = {0};

		treeCoin_ToF->SetBranchAddress("tsSlc0_ToF", &tsSlc0_ToF);
		treeCoin_ToF->SetBranchAddress("tmStp0_ToF", &tmStp0_ToF);
		treeCoin_ToF->SetBranchAddress("nCoin_ToF", &nCoin_ToF);
		treeCoin_ToF->SetBranchAddress("nHit_ToF", nHit_ToF);
		treeCoin_ToF->SetBranchAddress("tmCrs_ToF", tmCrs_ToF);
		treeCoin_ToF->SetBranchAddress("tsFine_ToF", tsFine_ToF);
		treeCoin_ToF->SetBranchAddress("tsSlc_ToF", tsSlc_ToF);

		double calTimeFine[NBD_ToF][NCH_Start_ToF][NTDL_ToF] = {0};
		TH1F *hTsFine[NBD_ToF][NCH_Start_ToF], *hSumTsFine[NBD_ToF][NCH_Start_ToF];
		long long nData[NBD_ToF][NCH_Start_ToF] = {0};

		for (j = 0; j < NBD_ToF; j++)
			for (k = 0; k < NCH_Start_ToF; k++)
			{
				string sHist = "hTsFine_Bd" + to_string(j) + "_Ch" + to_string(k);
				string sDraw = "tsFine_ToF[" + to_string(j) + "][" + to_string(k) + "][0]>>" + sHist + "(" + to_string(NTDL_ToF) + ",0," + to_string(NTDL_ToF) + ")";
				string sCut = "nCoin_ToF>=2 && tsFine_ToF[" + to_string(j) + "][" + to_string(k) + "][0]>0 && nHit_ToF[" + to_string(j) + "][" + to_string(k) + "]>0";

				nData[j][k] = treeCoin_ToF->Draw(sDraw.c_str(), sCut.c_str(), "goff");
				if (nData[j][k] < 10)
					continue;

				hTsFine[j][k] = (TH1F *)(gDirectory->Get(sHist.c_str()));
				hTsFine[j][k]->SetTitle(("TsFine_Bd" + to_string(j) + "_Ch" + to_string(k) + ";Bin;Counts").c_str());

				string sHistSum = "hSumTsFine_Bd" + to_string(j) + "_Ch" + to_string(k);
				hSumTsFine[j][k] = new TH1F(sHistSum.c_str(), "", NTDL_ToF, 0, NTDL_ToF);

				y = hTsFine[j][k]->Integral();
				z = 0.0;
				m = NCH_ToF * j + k;
				for (i = 1; i <= NTDL_ToF; i++)
				{
					z += hTsFine[j][k]->GetBinContent(i);
					// hSumTsFine[k]->SetBinContent(i, z);
					calTimeFine[j][k][i - 1] = z / y * TimeCrs_ToF;
					hSumTsFine[j][k]->SetBinContent(i, calTimeFine[j][k][i - 1]);
				}
			}
		TCanvas *c1 = new TCanvas(("TsFine_" + sRun_ToF).c_str(), ("TsFine_" + sRun_ToF).c_str(), 1200 * 8, 900 * 4);
		c1->Divide(NBD_ToF, max(NCH_Start_ToF,NCH_Stop_ToF));
		TGaxis *axis[NBD_ToF][NCH_Start_ToF];
		for (j = 0; j < NBD_ToF; j++)
			for (k = 0; k < NCH_Start_ToF; k++)
				if (nData[j][k] > 10)
				{
					m = NCH_Start_ToF * j + k;
					c1->cd(m + 1);

					hTsFine[j][k]->Draw();
					hTsFine[j][k]->GetXaxis()->CenterTitle();
					gPad->Update();
					x = 1.1 * hSumTsFine[j][k]->GetMaximum();
					y = gPad->GetUymax() / x;
					hSumTsFine[j][k]->SetLineColor(kRed);
					hSumTsFine[j][k]->Scale(y);
					hSumTsFine[j][k]->Draw("same HIST");
					axis[j][k] = new TGaxis(gPad->GetUxmax(), gPad->GetUymin(), gPad->GetUxmax(), gPad->GetUymax(), 0, x, 510, "+L");
					axis[j][k]->SetLineColor(kRed);
					axis[j][k]->SetLabelColor(kRed);
					axis[j][k]->Draw();
				}
		c1->SaveAs(("../Graphs/TsFine_" + sRun_ToF + ".png").c_str());
		for (j = 0; j < NBD_ToF; j++)
			for (k = 0; k < NCH_Start_ToF; k++)
				if (nData[j][k] > 10)
				{
					delete axis[j][k];
					delete hSumTsFine[j][k];
				}
		delete c1;

		TFile *fAna = new TFile(sAna.c_str(), "RECREATE");
		TTree *treeAna_ToF = new TTree("treeAna_ToF", "tree for analyzed ToF data");

		short nPair_tDif = 0;
		double tmDif[NAllCH_ToF][NAllCH_ToF] = {0}, ToF = 0;
		double tmDif_ToF[NAllCH_ToF][NAllCH_ToF] = {0};
		double tmDif_Tstart[NAllCH_ToF][NAllCH_ToF] = {0};
		double tmDif_Tstop[NAllCH_ToF][NAllCH_ToF] = {0};
		double timeCh[2][NAllCH_ToF] = {0};

		treeAna_ToF->Branch("sRun_ToF", &sRun_ToF);
		treeAna_ToF->Branch("tsSlc0_ToF", &tsSlc0_ToF, "tsSlc0_ToF/L");
		treeAna_ToF->Branch("tmStp0_ToF", &tmStp0_ToF, "tmStp0_ToF/D");
		treeAna_ToF->Branch("nPair_tDif", &nPair_tDif, "nPair_tDif/S");
		treeAna_ToF->Branch("tmDif_Tstart", tmDif_Tstart, ("tmDif_Tstart[" + to_string(NAllCH_ToF) + "][" + to_string(NAllCH_ToF) + "]/D").c_str());
		treeAna_ToF->Branch("tmDif_Tstop", tmDif_Tstop, ("tmDif_Tstop[" + to_string(NAllCH_ToF) + "][" + to_string(NAllCH_ToF) + "]/D").c_str());
		treeAna_ToF->Branch("tmDif_ToF", tmDif_ToF, ("tmDif_ToF[" + to_string(NAllCH_ToF) + "][" + to_string(NAllCH_ToF) + "]/D").c_str());
		treeAna_ToF->Branch("timeCh", timeCh, ("timeCh[" + to_string(2) + "][" + to_string(NAllCH_ToF) + "]/D").c_str());
		treeAna_ToF->Branch("tmDif", tmDif, ("tmDif[" + to_string(NAllCH_ToF) + "][" + to_string(NAllCH_ToF) + "]/D").c_str());
		treeAna_ToF->Branch("ToF", &ToF, "ToF/D");

		long long iEnt = 0, nEnt = treeCoin_ToF->GetEntries();
		p = 0;
		for (iEnt = 0; iEnt < nEnt; iEnt++)
		{
			nPair_tDif = 0;
			memset(tmDif, 0, sizeof(tmDif));
			memset(tmDif_ToF, 0, sizeof(tmDif_ToF));
			ToF = 0;

			treeCoin_ToF->GetEntry(iEnt);

			if (nCoin_ToF >= 2 && TStartExit && TStopExit)
			{
				for (i = 0; i < NCH_Start_ToF; i++)
				{
					if (nHit_ToF[0][i] <= 0)
						continue;
					for (j = 0; j < NCH_Stop_ToF; j++)
					{
						if (nHit_ToF[1][j] <= 0)
							continue;
						tmDif_ToF[i][j] = (tmCrs_ToF[0][i][0] - tmCrs_ToF[1][j][0]) - (calTimeFine[0][i][tsFine_ToF[0][i][0]] - calTimeFine[1][j][tsFine_ToF[1][j][0]]);

						tmDif_ToF[j][i] = -tmDif_ToF[i][j];

						nPair_tDif++;

						ToF += tmDif_ToF[i][j];
					}
				}
				ToF = ToF / nPair_tDif;
			}
			if (TStartExit)
			{
				for (i = 0; i < NCH_Start_ToF; i++)
				{
					if (nHit_ToF[0][i] <= 0)
						continue;
					timeCh[0][i] = tmCrs_ToF[0][i][0] - calTimeFine[0][i][tsFine_ToF[0][i][0]];
					for (j = i + 1; j < NCH_Start_ToF; j++)
					{
						if (nHit_ToF[0][j] <= 0)
							continue;
						tmDif_Tstart[i][j] = (tmCrs_ToF[0][i][0] - tmCrs_ToF[0][j][0]) - (calTimeFine[0][i][tsFine_ToF[0][i][0]] - calTimeFine[0][j][tsFine_ToF[0][j][0]]);

						tmDif_Tstart[j][i] = -tmDif_Tstart[i][j];
						nPair_tDif++;
					}
				}
			}
			if (TStopExit)
			{
				for (i = 0; i < NCH_Stop_ToF; i++)
				{
					if (nHit_ToF[1][i] <= 0)
						continue;
					timeCh[1][i] = tmCrs_ToF[0][i][0] - calTimeFine[0][i][tsFine_ToF[0][i][0]];
					for (j = i + 1; j < NCH_Stop_ToF; j++)
					{
						if (nHit_ToF[1][j] <= 0)
							continue;
						tmDif_Tstop[i][j] = (tmCrs_ToF[1][i][0] - tmCrs_ToF[1][j][0]) - (calTimeFine[1][i][tsFine_ToF[1][i][0]] - calTimeFine[1][j][tsFine_ToF[1][j][0]]);

						tmDif_Tstop[j][i] = -tmDif_Tstop[i][j];

						nPair_tDif++;
					}
				}
			}

			if (nPair_tDif > 0)
				treeAna_ToF->Fill();

			if ((10.0 * iEnt / nEnt) >= p)
			{
				printf("**********%d%% of %lld events of %s have been processed!**********\n", 10 * p, nEnt, sRun_ToF.c_str());
				p++;
			}
		}
		fAna->cd();
		treeAna_ToF->Write("", TObject::kOverwrite);
		fAna->Close();
		delete fAna;
		fCoin->Close();
		delete fCoin;

		finish = clock();
		cout << "\nTime for processing Run#" << sRun_ToF << " is: " << double(finish - start) / CLOCKS_PER_SEC << " s\n\n";
	}
}
#ifndef __CINT__
int main(int argc, char **argv)
{
	Coin2Ana_ToF();
	return 0;
}
#endif
